use tracing_appender::{
    non_blocking::WorkerGuard,
    rolling::{RollingFileAppender, Rotation},
};
use tracing_bunyan_formatter::{BunyanFormattingLayer, JsonStorageLayer};
use tracing_log::LogTracer;
use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry};

/// Init logging and tracing.
pub fn init_global_tracing(
    app_name: &str,
    dir: &str,
    level: &str,
    enable_stdout: Option<bool>,
) -> Vec<WorkerGuard> {
    let mut guards = vec![];

    // Enable log compatible layer to convert log record to tracing span.
    LogTracer::init().expect("log tracer must be valid");

    // JSON layer:
    // Log files will be stored in log.dir, default is './logs'.
    let rolling_appender = RollingFileAppender::new(Rotation::HOURLY, dir, app_name);
    let (rolling_writer, rolling_writer_guard) = tracing_appender::non_blocking(rolling_appender);
    let file_logging_layer = BunyanFormattingLayer::new(app_name.to_owned(), rolling_writer);
    guards.push(rolling_writer_guard);

    let stdout_layer = if enable_stdout == Some(false) {
        None
    } else {
        Some(tracing_subscriber::fmt::layer().with_ansi(atty::is(atty::Stream::Stdout)))
    };

    // Use env RUST_LOG to initialize log if present.
    // Otherwise, use the specified level.
    let directives = std::env::var(EnvFilter::DEFAULT_ENV).unwrap_or_else(|_x| level.to_owned());
    let env_filter = EnvFilter::new(directives);
    let subscriber = Registry::default()
        .with(stdout_layer)
        .with(env_filter)
        .with(JsonStorageLayer)
        .with(file_logging_layer);

    // For tokio-console
    #[cfg(feature = "console")]
    let subscriber = subscriber.with(console_subscriber::spawn());

    tracing::subscriber::set_global_default(subscriber)
        .expect("error setting global tracing subscriber");

    guards
}
